#include "StdAfx.h"
#include "AdpcmPlayer.h"


//-----------------------------CONSTRUCTOR & DESTRUCTOR-------------------------

AdpcmPlayer::AdpcmPlayer(int channels, int sampleRate, int bitsPerSample, AudioCodecId codecId)
	:m_channels(channels),
	m_sampleRate(sampleRate),
	m_bitsPerSample(bitsPerSample),
	m_isInitialized(false),
	m_codecId(codecId)
{
	if (InitPlayer() < 0)
		return;

	if (!StartPlay())
		DestroyPlayer();
}

AdpcmPlayer::~AdpcmPlayer(void)
{
	DestroyPlayer();
}

//------------------------------------------------------------------------------

int AdpcmPlayer::PlaybackAudioData(char *data, int len)
{
	if (!m_isInitialized)
		return ADPCMSDK_ERROR_BAD_SESSION;

	return m_sourceFilter->PlayAdpcmData(data, len);
}

int AdpcmPlayer::GetVolume()
{
	if (!m_isInitialized)
		return ADPCMSDK_ERROR_BAD_SESSION;

	CComQIPtr<IBasicAudio> audioCtrl(m_filterGraph);
	if (audioCtrl == NULL)
		return ADPCMSDK_ERROR_OPERATION_FAILED;

	long volume;
	HRESULT hr = audioCtrl->get_Volume(&volume);
	if (FAILED(hr))
		return ADPCMSDK_ERROR_OPERATION_FAILED;

	return volume / 100 + 100;
}

int AdpcmPlayer::SetVolume(int volume)
{
	if (!m_isInitialized)
		return ADPCMSDK_ERROR_BAD_SESSION;

	if (volume < MIN_VOLUME || volume > MAX_VOLUME)
		return ADPCMSDK_ERROR_INVALID_PARAM;

	CComQIPtr<IBasicAudio> audioCtrl(m_filterGraph);
	if (audioCtrl == NULL || FAILED(audioCtrl->put_Volume((volume - 100) * 100)))
		return ADPCMSDK_ERROR_OPERATION_FAILED;

	return ADPCMSDK_SUCCESS;
}

//------------------------------------------------------------------------------

bool AdpcmPlayer::StartPlay()
{
	InitPlayer();

	if (!m_isInitialized)
		return true;

	//CComQIPtr<IMediaSeeking> mediaSeeking(m_filterGraph);
	//if (mediaSeeking == NULL)
	//	return false;

	//LONGLONG position = 0;
	//if (FAILED(mediaSeeking->SetPositions(&position, AM_SEEKING_AbsolutePositioning, NULL, AM_SEEKING_NoPositioning)))
	//	return false;

	CComQIPtr<IMediaControl> mediaControl(m_filterGraph);
	if (mediaControl == NULL)
		return false;

	mediaControl->Stop();	//for replay,the previous play must be stop first.

	if (FAILED(mediaControl->Run()))
	{
		mediaControl->Stop();	//although graph is not running,but some filters may be running.

		return false;
	}

	return true;
}

void AdpcmPlayer::StopPlay()
{
	if (!m_isInitialized)
		return;

	//if (m_sourceFilter.get() != NULL)
	//	m_sourceFilter->StopPlay();

	CComQIPtr<IMediaControl> mediaControl(m_filterGraph);
	if (mediaControl != NULL)
		mediaControl->Stop();
}

int AdpcmPlayer::InitPlayer()
{
#define ERROR_RETURN { m_filterGraph.Release(); m_sourceFilter.reset(); return -1;}
#define CHECK_RESULT(hr) if (FAILED(hr)) ERROR_RETURN;

	if (m_isInitialized)
		return 0;

	//create a audio playback DirectShow graph

	m_filterGraph.CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER);
	if (m_filterGraph == NULL)
		ERROR_RETURN;

	HRESULT hr;
	m_sourceFilter = auto_ptr<CPushSourceAdpcmAudio>(new CPushSourceAdpcmAudio(NULL, &hr, m_channels, m_sampleRate, m_bitsPerSample, m_codecId));
	CHECK_RESULT(hr);

	hr = m_filterGraph->AddFilter(m_sourceFilter.get(), L"PCM Audio Source");
	CHECK_RESULT(hr);

	hr = m_filterGraph->Render(m_sourceFilter->GetOutputPin());
	CHECK_RESULT(hr);

	m_isInitialized = true;

	return 0;
}

int AdpcmPlayer::DestroyPlayer()
{
	StopPlay();

	//release all resources for audio playback(if exists)
	m_filterGraph.Release();
	m_sourceFilter.reset();

	m_isInitialized = false;

	return 0;
}
